﻿using System.Text.Encodings.Web;
using System.Text.Json;
using System.Text.Unicode;
using Microsoft.EntityFrameworkCore;
using RotovapPlatform.Domain.Business.Recipes.Entities;
using RotovapPlatform.Domain.Business.Recipes.Entities.Parameters;
using System.Diagnostics;
using System.Collections.ObjectModel;
using System.IO;
using System;

namespace RotovapPlatform.Infrastructure.Common.Data;

/// <summary>
/// 实验组数据库上下文
/// 负责管理实验组的数据访问和持久化
/// </summary>
public class ExperimentGroupDbContext : DbContext
{
	/// <summary>
	/// 实验组数据集
	/// </summary>
	public DbSet<ExperimentGroup> ExperimentGroups { get; set; }

	/// <summary>
	/// 实验数据集（用于关联）
	/// </summary>
	public DbSet<Experiment> Experiments { get; set; }

	/// <summary>
	/// 构造函数
	/// </summary>
	/// <param name="options">数据库上下文配置选项</param>
	public ExperimentGroupDbContext(DbContextOptions<ExperimentGroupDbContext> options)
		: base(options)
	{
		Debug.WriteLine($"ExperimentGroupDbContext created with options: {options.ContextType}");
	}

	/// <summary>
	/// 配置实体模型
	/// </summary>
	/// <param name="modelBuilder">模型构建器</param>
	protected override void OnModelCreating(ModelBuilder modelBuilder)
	{
		Debug.WriteLine("Configuring ExperimentGroupDbContext model...");

		base.OnModelCreating(modelBuilder);

		modelBuilder.Entity<ExperimentGroup>(entity =>
		{
			entity.ToTable("ExperimentGroups");
			entity.HasKey(e => e.GroupId);
			entity.Property(e => e.GroupName).IsRequired().HasMaxLength(100);
			entity.Property(e => e.Description).IsRequired(false).HasMaxLength(500);
			entity.Property(e => e.Creator).IsRequired(false).HasMaxLength(50);
			entity.Property(e => e.CreatedTime).IsRequired();
			entity.Property(e => e.ErrorMessage).IsRequired(false);

			// 配置与实验的关系
			entity.HasMany(e => e.Experiments)
				  .WithOne()
				  .HasForeignKey(e => e.ExperimentGroupId)
				  .OnDelete(DeleteBehavior.Cascade);

			// 配置与配方的关系
			var jsonOptions = new JsonSerializerOptions
			{
				Encoder = JavaScriptEncoder.Create(UnicodeRanges.All),
				WriteIndented = true
			};

			entity.Property(e => e.Recipes)
				.HasConversion(
					v => JsonSerializer.Serialize(v, jsonOptions),
					v => JsonSerializer.Deserialize<ObservableCollection<RecipeDefinition>>(v, jsonOptions) ??
						 new ObservableCollection<RecipeDefinition>()
				);
		});

		// 由于Experiments表已经由ExperimentDbContext创建，这里只配置关系，不创建表
		// 使用HasNoKey()方法告诉EF Core这个实体在当前上下文中不需要主键
		modelBuilder.Entity<Experiment>(entity =>
		{
			entity.ToTable("Experiments", t => t.ExcludeFromMigrations());

			// 配置ExecutionParameters为JSON字符串
			var jsonOptions = new JsonSerializerOptions
			{
				Encoder = JavaScriptEncoder.Create(UnicodeRanges.All),
				WriteIndented = true
			};

			entity.Property(e => e.ExecutionParameters)
				  .HasConversion(
					  v => JsonSerializer.Serialize(v, jsonOptions),
					  v => JsonSerializer.Deserialize<RotovapPlatform.Domain.Business.Recipes.Entities.Parameters.RotovapParameters>(v, jsonOptions)
				  );
		});

		// 忽略所有参数类型，它们应该作为JSON存储而不是单独的表
		modelBuilder.Ignore<RotovapPlatform.Domain.Business.Recipes.Entities.Parameters.ProductParameters>();
		modelBuilder.Ignore<RotovapPlatform.Domain.Business.Recipes.Entities.Parameters.ResidualLiquidParameters>();
		modelBuilder.Ignore<RotovapPlatform.Domain.Business.Recipes.Entities.Parameters.CleaningParameters>();
		modelBuilder.Ignore<RotovapPlatform.Domain.Business.Recipes.Entities.Parameters.RotovapParameters>();

		// 完全忽略RecipeDefinition类型，因为它已经在ExperimentDbContext中定义
		modelBuilder.Ignore<RecipeDefinition>();

		Debug.WriteLine("Model configuration completed");
	}

	/// <summary>
	/// 配置数据库连接
	/// </summary>
	/// <param name="optionsBuilder">数据库配置构建器</param>
	protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
	{
		if (!optionsBuilder.IsConfigured)
		{
			var solutionDir = Path.GetFullPath(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "..\\..\\..\\..\\.."));
			var infrastructureDir = Path.Combine(solutionDir, "src", "RotovapPlatform.Infrastructure");
			var folder = Path.Combine(infrastructureDir, "Data");

			if (!Directory.Exists(folder))
			{
				Directory.CreateDirectory(folder);
			}

			var dbPath = Path.Combine(folder, "Rotovap.db");
			optionsBuilder.UseSqlite($"Data Source={dbPath}");
		}
	}
}